game = {}

function Reshuffle()
  local maxd = 50
	x = love.math.random(b.l,b.r)
	y = love.math.random(b.u,b.b)
  if (x < 50 and x > -50) or (y < 50 and y > -50) then
      x,y = Reshuffle()
  end
  return x,y
end

function newRabbit()
  local rx,ry = Reshuffle()
  return {
    x = rx,
    y = ry,
    nx= rx,
    ny= ry,
    ms= 350 ,-- max speed
    s = 0 ,-- speed
    p = 0 ,-- power
    a = 3 ,--acceleration
    rt= 0 ,--rotation
    j = false ,--jumped
    score = 0,
    presents = {},
    nickname = "wtf no name??",
    }
end

function newPresent()
  local rx,ry = Reshuffle()
  return {
    x = rx,
    y = ry,
	  w = 50,
	  h = 50,
    r = .5 + .5 * math.random(),
    g = .5 + .5 * math.random(),
    b = .5 + .5 * math.random(),
    }
end

function game.load()
  lg.clear()
  --defining global values
  b = { --borders
    u = -1000,
    b = 1000,
    l = -1000,
    r = 1000,
  }

  rb = newRabbit()

  treeSprite = lg.newImage("tree.png")
  rbSprite = lg.newImage("rabbit.png")
  trapSprite = lg.newImage("trap.png")
  presentSprite = lg.newImage("present.png")

  local w = lg.getWidth()/2
  local h = lg.getHeight()/2
  local camx = -rb.x + w
  local camy = -rb.y + h
  lg.translate(camx,camy)

  --client stuff 
  client = sock.newClient(server, port)
  client:setSerialization(bitser.dumps, bitser.loads)

  client:on("connect", function(data) print("connected!") end)
  client:on("disconnect",function()
    tick.delay(function()
    love.event.quit() end, .1
  )
  end
)

  client:on("playerNum", function(num)
      playerNum = num
      client:send("setName",{num,nickname})
  end)

  client:on("tooManyPlayers",function() client:disconnect(playerNum) love.event.quit() end)

  client:on("playerLeft", function(i)
    if i == playerNum then return end
    table.remove(players,i)
      if i < playerNum then
        playerNum = playerNum - 1
      end
    end
  )

  client:setSchema("playerConnected",{
    "id", "players"
  })
  client:on("playerConnected", function(d)
    --table.insert(players,d.id,d.player)
    players = d.players
  end)

  client:setSchema("playerState", {
    "id",
    "x",
    "y",
    "ppr",
    "score",
  })
  client:on("playerState", function(d)
      if #players <= 1
      or players[d.id] == nil then return end
      players[d.id].score = d.score
      if d.id == playerNum then return end
      players[d.id].x = d.x
      players[d.id].y = d.y
      players[d.id].presents = d.ppr
    end
  )

  client:on("trapState", function(t)
    traps = t
    end
  )
  client:on("presentState", function(p)
    presents = p
    end
  )

  client:setSchema("rotatePlayer",{
    "id",
    "rt"
  })
  client:on("rotatePlayer",function(d)
    if d.id ~= playerNum and players[d.id] ~= nil and d.rt ~= nil then 
      players[d.id].rt = d.rt
    end
    end
  )

  client:connect()
end

function game.update(dt)
  tick.update(dt)
  client:update()
  if lk.isDown("space") and not rb.j then
    if rb.p < rb.ms then
      rb.p = rb.p + 10
    end
  end
  if lk.isDown("a") and not rb.j then
    rb.rt = rb.rt - rb.a * dt
    client:send("rotatePlayer",{playerNum,rb.rt})
  elseif lk.isDown("d") and not rb.j then
    rb.rt = rb.rt + rb.a * dt
    client:send("rotatePlayer",{playerNum,rb.rt})
  end
  local cos = math.cos(rb.rt)
  local sin = math.sin(rb.rt)
for i,p in ipairs(rb.presents) do
    local d = 25
    if i == 1 then
      if lume.distance(p.x,p.y,rb.x,rb.y) > d then
        p.x = lume.smooth(p.x,rb.x,.1)
        p.y = lume.smooth(p.y,rb.y,.1)
      end
    else
      if lume.distance(p.x,p.y,rb.presents[i-1].x,rb.presents[i-1].y) > d then
        p.x = lume.smooth(p.x,rb.presents[i-1].x,.1)
        p.y = lume.smooth(p.y,rb.presents[i-1].y,.1)
      end
    end
  end
  rb.y = rb.y + rb.s * dt * sin
  rb.x = rb.x + rb.s * dt * cos
  if rb.s > 0 then 
    rb.s = rb.s - rb.a * dt * 100 
  elseif rb.s <= 0 and rb.j then
    rb.s = 0 
    rb.j = false 
    checkCollision(rb)
    if lume.distance(rb.x,rb.y,0,0) < 100 and #presents > 0 then
      rb.presents = {}
    end 
  end
  if playerNum ~= nil then
     client:send("playerUpdate",{playerNum,rb.x,rb.y,rb.presents,rb.score})
  end
end

function game.keyreleased(k)
  if k == "space" and not rb.j then
    rb.j = true
    rb.s = rb.p
    rb.p = 0
  elseif k == "escape" then 
    client:send("pred",playerNum)
  end
end

function love.quit()
  if client ~= nil and client:isConnected() then
    table.remove(players,playerNum)
    client:send("pred",playerNum)
    return true
  end
end

function checkCollision()
  local function checkOnTables(t,fx)
    if t ~= nil then
        for i,p in ipairs(t) do
          local sqrSize = 10
           if p.x - 25 < rb.x + sqrSize
          and p.x + 25 > rb.x - sqrSize 
          and p.y - 25 < rb.y + sqrSize
          and p.y + 25 > rb.y - sqrSize then
              fx(i,p)
          end
        end
    end
  end
  if #rb.presents <= 14 then
  checkOnTables(presents, function(i,p)
            rb.score = rb.score + 1
            table.insert(rb.presents,p)
            table.remove(presents,i)
            local p = newPresent()
            table.insert(presents,i,p)
    end
    
  )
  end

  checkOnTables(traps, function(i,p)
    client:send("pred",playerNum)
    end
  )
  client:send("playerCollided",presents)
end

function game.draw()
  lg.push()
  local w = lg.getWidth()/2
  local h = lg.getHeight()/2
  local camx = -rb.x + w
  local camy = -rb.y + h
  if camx < -b.r + w then
    camx = -b.r + w 
  elseif camx > -b.l + w then
    camx = -b.l + w
  end
  if camy < -b.b + h then
    camy = -b.b + h 
  elseif camy > -b.u + h then
    camy = -b.u + h
  end
  lg.translate(camx,camy)
  lg.setBackgroundColor(1,1,1)
  lg.setColor(1,1,1)

  local function drawTable(t,s)
    local t = t or {}
    for _,i in ipairs(t) do
        if i.r ~= nil then
          lg.setColor(i.r,i.g,i.b)
        end
    local a = i.a or 0
    lg.draw(s,i.x,i.y,a,1,1,25,25)
    end
  end

  drawTable(presents,presentSprite)
  drawTable(rb.presents,presentSprite)
  drawTable(traps,trapSprite)

  lg.setColor(1,1,1)

  for i,p in ipairs(players) do
    if i ~= playerNum then
      lg.setColor(1,1,1)
      lg.draw(rbSprite,p.x,p.y,p.rt,1,1,25,25)
      for j,r in ipairs(p.presents) do
        lg.setColor(r.r,r.g,r.b)
        lg.draw(presentSprite,r.x,r.y,0,1,1,25,25)
      end
    lg.setColor(0,0,0)
    lg.print(p.nickname,p.x -  25 + #p.nickname/2,p.y + 25)
    end
  end
 
  lg.setColor(1,1,1)
  lg.draw(treeSprite,-150/2,-150+10)
  lg.draw(rbSprite,rb.x,rb.y, rb.rt,1 + rb.s * .001,1 + rb.s * .001,25,25)
  lg.setColor(0,0,0)
  lg.print(nickname,rb.x -  25 + #nickname/2,rb.y + 25)
  lg.setColor(1,1,1)
  lg.pop()
  lg.setColor(1,.4,.2)
    local function drawBoid (mode, x, y, length, width , angle) -- position, length, width and angle
      	love.graphics.push()
      	love.graphics.translate(x, y)
      	love.graphics.rotate( angle )
      	love.graphics.polygon(mode, -length/2, -width /2, -length/2, width /2, length/2, 0)
      	love.graphics.pop() 
    end
    drawBoid("fill",30,lg.getHeight() - 40, 40,30,lume.angle(rb.x,rb.y,0,0))
  if rb.p > 0 then
    lg.rectangle("fill",10,10,rb.p/5,10,4,4)
  end
  lg.setColor(0,0,0)
  local bestScore = lume.sort(players,"score")
  for i = #bestScore, #bestScore - 5, -1 do
    if i > 0 then
      local p = bestScore[i]
      local num = #bestScore - i + 1
      lg.print(num..". "..p.nickname.." - "..p.score,lg.getWidth() - 250, lg.getHeight() - 70 - i*10)
    end
  end
  lg.print("score : "..rb.score,lg.getWidth() - 10 * string.len("score : "..rb.score) - 10,10)
end

return game
